Skip to content

学习周报-2025-03-16

JavaScript的数字精度问题

toFixed的结果可能会欺骗你【渡一教育】_哔哩哔哩_bilibili

先看下面的代码:

ts
1.45.toFixed(1); // 1.4
2.45.toFixed(1); // 2.5

问题的原因是 JavaScript 的存储和操作各种数字都是基于二进制的,而二进制无法准确表示小数。

存储精度问题

可以使用 .toString(2) 方法获取一个数字的二进制表示,这时会发现大多数小数的二进制表示是无限重复的。

存储时,小数部分会被截断。如果截断位置是 0,结果会变小,如果截断位置是 1,结果会变大。

可以使用 .toPrecision() 方法将数字转换为指定精度的字符串,这样就可以清楚地看到问题。

例如:

ts
console.log(1.45.toPrecision(50)); // '1.4499999999999999555910790149937383830547332763672'
console.log(2.45.toPrecision(50)); // '2.4500000000000001776356839400250464677810668945313'

这里可以看到,1.45 转换后结果变小,2.45 转换后结果变大。

操作精度问题

当进行操作时,使用二进制进行操作,所以也可能存在精度问题。

例如:

ts
console.log(0.1 + 0.2); // 0.30000000000000004

显示精度问题

虽然存储不准确,但浏览器会进行近似处理,所以在控制台中显示是正确的。

ts
console.log(0.3) // 0.3
console.log(0.3.toPrecision(50)) // '0.29999999999999998889776975374843459576368331909180'
console.log(0.29999999999999998889776975374843459576368331909180) // 0.3
console.log(0.3 === 0.29999999999999998889776975374843459576368331909180) // true

基于 toFixed() 方法的 1.45 和 2.45 精度问题

ts
console.log(1.45.toString(2)) // 1.0111001100110011001100110011001100110011001100110011
console.log(1.45.toPrecision(50)); // '1.4499999999999999555910790149937383830547332763672'
console.log(2.45.toString(2)) // 10.01110011001100110011001100110011001100110011001101
console.log(2.45.toPrecision(50)); // '2.4500000000000001776356839400250464677810668945313'

因为 2.45 的整数部分是 10,占据 2 位,而 1.45 的整数部分是 1,只占据 1 位,所以虽然理论上 1.45 和 2.45 的小数部分是相同的,但在实际存储时,2.45 的存储位数会更少,导致四舍五入后的结果不同。